home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / FinderFlocks / FinderFun / FinderFun.cp < prev    next >
Encoding:
Text File  |  1996-06-23  |  15.7 KB  |  551 lines  |  [TEXT/CWIE]

  1. // FinderFun.cp
  2. #include "FinderFun.h"
  3.  
  4. #define    kIconSize        1024    // The size of an icl8
  5. #define    kMaskSize        256        // The size of an ICN# (icon and mask, each 128)
  6. #define    kSmallIconSize    256        // The size of an ics8
  7. #define    kSmallMaskSize    64        // The size of an ics# (icon and mask, each 32)
  8.  
  9. extern long            gNumItems;
  10. extern Handle        gIcons[];
  11. extern Handle        gMasks[];
  12. extern Point        gPositions[];
  13. extern Rect            gWindowRect;
  14. extern long            gWindowView;
  15.  
  16. //----------------------------------------------------------------------------------------
  17. // FindPSNbyTypeAndSig: 
  18. //
  19. //    Find the PSN of some process, given its type and creator
  20. //----------------------------------------------------------------------------------------
  21. void FindPSNbyTypeAndSig(ProcessSerialNumber* psn, OSType type, OSType sig)
  22. {    
  23.     ProcessInfoRec            theProc;
  24.         
  25.     //
  26.     // Start out with kNoProcess
  27.     //
  28.     psn->highLongOfPSN = 0;
  29.     psn->lowLongOfPSN = kNoProcess;
  30.     
  31.     //
  32.     // Initialize fields in the ProcessInfoRec,
  33.     // or we'll have memory hits in random locations
  34.     //
  35.     theProc.processInfoLength = sizeof( ProcessInfoRec );
  36.     theProc.processName = nil;
  37.     theProc.processAppSpec = nil;
  38.     theProc.processLocation = nil;
  39.     
  40.     while(true)
  41.     {
  42.         OSErr        theErr;
  43.         
  44.         //
  45.         // Keep looking for the Finder until we find it
  46.         //
  47.         FailErr(GetNextProcess(psn));
  48.         if( (psn->highLongOfPSN == 0) && (psn->lowLongOfPSN == kNoProcess) )
  49.             Throw(procNotFound);
  50.         
  51.         //
  52.         // Is the current process the one we're looking for?
  53.         //
  54.         FailErr(GetProcessInformation(psn, &theProc));
  55.         if( (theProc.processType == type ) && (theProc.processSignature == sig) )
  56.             break;
  57.     }
  58. } // FindPSNbyTypeAndSig 
  59.  
  60. //----------------------------------------------------------------------------------------
  61. // GetAddressOfFinder: 
  62. //
  63. //    Generate an address for the Finder on this machine 
  64. //----------------------------------------------------------------------------------------
  65. TDescriptor GetAddressOfFinder()
  66. {
  67.     ProcessSerialNumber finderPSN;
  68.     TDescriptor finderAddressDescriptor;
  69.     
  70.     //
  71.     // Find the Finder's PSN
  72.     //
  73.     FindPSNbyTypeAndSig(&finderPSN, 'FNDR', 'MACS');
  74.     
  75.     //
  76.     // Copy the target ID into a descriptor
  77.     //
  78.     finderAddressDescriptor.MakeProcessSerialNumber(finderPSN);
  79.     
  80.     return finderAddressDescriptor;
  81. } // GetAddressOfFinder 
  82.  
  83. //----------------------------------------------------------------------------------------
  84. // MakeSpecifierForFrontWindow
  85. //----------------------------------------------------------------------------------------
  86. TDescriptor MakeSpecifierForFrontWindow()
  87. {
  88.     TDescriptor nullDescriptor;
  89.     
  90.     return MakeSpecifierForIndexedItem(cWindow, 1, nullDescriptor);
  91. }
  92.  
  93. //----------------------------------------------------------------------------------------
  94. // MakeSpecifierForIndexedItem
  95. //----------------------------------------------------------------------------------------
  96. TDescriptor MakeSpecifierForIndexedItem(DescType desiredClass, long index, TDescriptor ofSpecifier)
  97. {
  98.     TDescriptor resultSpecifier; 
  99.     TDescriptor keyData;
  100.  
  101.     //
  102.     // Make a descriptor whose type is 'typeLongInteger' and whose
  103.     // contents is the index passed in.
  104.     //
  105.     keyData.MakeLong(index);
  106.     
  107.     //
  108.     // Make an object specifier for "<<class desiredClass>> index of <ofSpecifier>".
  109.     // The object specifier will contain the following:
  110.     //
  111.     // Desired class:        desiredClass            The class of the object being referenced;
  112.     //                                                examples include cWindow, cObject, cDisk,
  113.     //                                                cAliasFile, and many others
  114.     //
  115.     // Container:            ofSpecifier                Object specifiers are defined recursively
  116.     //
  117.     // Key form:            formAbsolutePosition    This indicates that we are accessing the
  118.     //                                                'index'th item of the container.  Another
  119.     //                                                choice would be formName, in which case
  120.     //                                                the key data would contain the name of the
  121.     //                                                object being referenced.
  122.     //
  123.     // Key data:            typeLongInteger /        formAbsolutePosition implies that the key data
  124.     //                        'index'                    will be an integer
  125.     //
  126.     // We pass 'false' to MakeObjectSpecifier, so our inputs are not disposed
  127.     // (we want to keep 'ofSpecifier' around).  Because we didn't ask MakeObjectSpecifier
  128.     // to delete our inputs, we'll have to delete the key data ourselves
  129.     //
  130.     resultSpecifier.MakeObjectSpecifier(desiredClass, ofSpecifier, formAbsolutePosition, keyData, false);
  131.     keyData.Dispose();
  132.  
  133.     return resultSpecifier;
  134. } // MakeSpecifierForSelection
  135.  
  136. //----------------------------------------------------------------------------------------
  137. // MakeSpecifierForPropertyOfSpecifier: 
  138. //
  139. //    This function makes an object specifier for "property of <<specifier provided>>"
  140. //----------------------------------------------------------------------------------------
  141. TDescriptor MakeSpecifierForPropertyOfSpecifier(DescType property, TDescriptor ofSpecifier)
  142. {
  143.     TDescriptor specifier;
  144.     TDescriptor keyData;
  145.     OSErr err = noErr;
  146.         
  147.     //
  148.     // Make a descriptor whose type is 'typeType', and whose
  149.     // contents are the property passed into this function.
  150.     //
  151.     keyData.MakeDescType(property);
  152.  
  153.     Try
  154.     {
  155.         //
  156.         // The next object specifier we make also specifies a property, so it
  157.         // will look very similar to the one we built above:
  158.         //
  159.         // Desired class        cProperty        Required to specify a property.
  160.         //
  161.         // Container            "ofSpecifier"    We are making a specifier for
  162.         //                                        "property of <ofSpecifier>", so clearly
  163.         //                                        our container must be the
  164.         //                                        object specifier passed in.
  165.         //
  166.         // Key form:            formPropertyID    Required to specify a property.
  167.         //
  168.         // Key data                typeType /        As before, the key data descriptor
  169.         //                        property        is typeType, and contains the property ID
  170.         //                                        that we wish to specify.
  171.         //
  172.         // This time we pass 'false' to MakeObjectSpecifier so that it will NOT dispose
  173.         // of its inputs when it is done.  Doing this leaves the keyData and ofSpecifier
  174.         // descriptors intact; we dispose of the key data, but leave the specifier that
  175.         // was passed into this function the responsibility of the caller.
  176.         //
  177.         specifier.MakeObjectSpecifier(cProperty, ofSpecifier, formPropertyID, keyData, false);
  178.         keyData.Dispose();
  179.     }
  180.     Catch(err)
  181.     {
  182.         //
  183.         // Note that 'MakeObjectSpecifier' might fail (out of memory, for example),
  184.         // so we must catch failures to dispose of the key data descriptor if necessary.
  185.         //
  186.         keyData.Dispose();
  187.         Throw(err);
  188.     }
  189.         
  190.     return specifier;
  191. } // MakeSpecifierForPropertyOfSpecifier 
  192.  
  193. //----------------------------------------------------------------------------------------
  194. // CountItemsInContainer
  195. //
  196. //    Returns the number of items of class 'desiredClass' inside the specified
  197. //    container.  The target application is specified in the parameter list.
  198. //----------------------------------------------------------------------------------------
  199. long CountItemsInContainer(DescType desiredClass, TDescriptor inContainer, TDescriptor target)
  200. {
  201.     TAEvent ae;
  202.     TAEvent reply;
  203.     TDescriptor keyData;
  204.     OSErr err = noErr;
  205.     long theCount = 0;
  206.     
  207.     Try
  208.     {
  209.         //
  210.         // Make a "Count elements" event
  211.         //
  212.         ae.MakeAppleEvent(kAECoreSuite, kAECountElements, target);
  213.         
  214.         //
  215.         // Put the direct object specifier into the direct object of our event
  216.         //
  217.         ae.PutDescriptor(keyDirectObject, inContainer);
  218.         
  219.         //
  220.         // Specify the class of things we want to count
  221.         //
  222.         keyData.MakeDescType(desiredClass);
  223.         ae.PutDescriptor(keyAEObjectClass, keyData);
  224.         keyData.Dispose();
  225.         
  226.         //
  227.         // Ask the question.  kAEWaitReply without filter procs is evil.
  228.         //
  229.         ae.Send(&reply, kAEWaitReply);
  230.         
  231.         //
  232.         // Extract the result out of the reply
  233.         //
  234.         theCount = reply.GetLongParameter(keyAEResult);
  235.     }
  236.     Catch(err)
  237.     {
  238.         //
  239.         // Any of a number of routines that we call above could
  240.         // fail; if they do, we need to dispose of any object
  241.         // that we created.
  242.         //
  243.         ae.Dispose();
  244.         reply.Dispose();
  245.         keyData.Dispose();
  246.         
  247.         Throw(err);
  248.     }
  249.     
  250.     return theCount;
  251. } // CountItemsInContainer
  252.  
  253. void GetFrontWindowInfo(long *numItems, Point *windPos, Rect *windRect, long *viewType)
  254. {
  255.     TDescriptor target;
  256.     TDescriptor frontWindowSpecifier;
  257.     TDescriptor    finderViewPrefsSpecifier;
  258.     TDescriptor    finderViewPrefs;
  259.     TDescriptor positionOfFrontWindowSpecifier;
  260.     TDescriptor positionOfFrontWindow;
  261.     TDescriptor boundsOfFrontWindowSpecifier;
  262.     TDescriptor boundsOfFrontWindow;
  263.     TDescriptor viewOfFrontWindowSpecifier;
  264.     TDescriptor viewOfFrontWindow;
  265.     TAEvent ae;
  266.     TAEvent reply;
  267.     OSErr err = noErr;
  268.     
  269.     Try
  270.     {
  271.         //
  272.         // Make the address of the finder, and an object specifier to
  273.         // the frontmost window.  We will use these descriptors a number
  274.         // of times.
  275.         //
  276.         target = GetAddressOfFinder();
  277.         frontWindowSpecifier = MakeSpecifierForFrontWindow();
  278.  
  279.         //
  280.         // Make a "GetData" event
  281.         //
  282.         ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  283.         
  284.         //
  285.         // Ask the Finder how many items are in the front window
  286.         //
  287.         *numItems = CountItemsInContainer(cObject, frontWindowSpecifier, target);
  288.         
  289.         // Ask the Finder about its view preferences
  290.         // !!!
  291.         
  292.         //
  293.         // Get the position of the front window
  294.         //
  295.         positionOfFrontWindowSpecifier = MakeSpecifierForPropertyOfSpecifier(pPosition, frontWindowSpecifier);
  296.         ae.PutDescriptor(keyDirectObject, positionOfFrontWindowSpecifier);
  297.         positionOfFrontWindowSpecifier.Dispose();
  298.  
  299.         //
  300.         // See notes on waitreply, elsewhere
  301.         //
  302.         ae.Send(&reply, kAEWaitReply);
  303.         
  304.         // Get the position out of the reply
  305.         positionOfFrontWindow = reply.GetDescriptor(keyAEResult);
  306.         *windPos = positionOfFrontWindow.GetPoint();
  307.         positionOfFrontWindow.Dispose();
  308.  
  309.         //
  310.         // Get the bounds of the front window
  311.         //
  312.         boundsOfFrontWindowSpecifier = MakeSpecifierForPropertyOfSpecifier(keyAEBounds, frontWindowSpecifier);
  313.         ae.PutDescriptor(keyDirectObject, boundsOfFrontWindowSpecifier);
  314.         boundsOfFrontWindowSpecifier.Dispose();
  315.  
  316.         //
  317.         // See notes on waitreply, elsewhere
  318.         //
  319.         ae.Send(&reply, kAEWaitReply);
  320.         
  321.         // Get the bounds out of the reply
  322.         boundsOfFrontWindow = reply.GetDescriptor(keyAEResult);
  323.         *windRect = boundsOfFrontWindow.GetRect();
  324.         boundsOfFrontWindow.Dispose();
  325.         
  326.         // Calculate the real rect, accounting for scrollbars and disk info
  327.         windRect->right -= 15;
  328.         windRect->bottom -= 15;
  329.         windRect->top += 20;
  330.         
  331.         //
  332.         // Get the view of the front window
  333.         //
  334.         viewOfFrontWindowSpecifier = MakeSpecifierForPropertyOfSpecifier(pView, frontWindowSpecifier);
  335.         ae.PutDescriptor(keyDirectObject, viewOfFrontWindowSpecifier);
  336.         viewOfFrontWindowSpecifier.Dispose();
  337.  
  338.         //
  339.         // See notes on waitreply, elsewhere
  340.         //
  341.         ae.Send(&reply, kAEWaitReply);
  342.         
  343.         // Get the view out of the reply
  344.         viewOfFrontWindow = reply.GetDescriptor(keyAEResult);
  345.         *viewType = viewOfFrontWindow.GetEnumeration();
  346.         viewOfFrontWindow.Dispose();
  347.         
  348.         target.Dispose();
  349.         frontWindowSpecifier.Dispose();
  350.     }
  351.     Catch(err)
  352.     {
  353.         //
  354.         // Any of a number of routines that we call above could
  355.         // fail; if they do, we need to dispose of any object
  356.         // that we created.
  357.         //
  358.         // Hah! not really doing it, am I? dkj
  359.         target.Dispose();
  360.         frontWindowSpecifier.Dispose();
  361.         
  362.         Throw(err);
  363.     }
  364. }
  365.  
  366. OSErr GetFinderItemInfo(short itemNum, Handle *theBits, Handle *theMaskBits, Point    *position)
  367. {
  368.     TDescriptor target;
  369.     TDescriptor frontWindowSpecifier;
  370.     TDescriptor iconFamilyForItem;
  371.     TDescriptor itemNOfFrontWindowSpecifier;
  372.     TDescriptor iconOfItemNSpecifier;
  373.     TDescriptor positionOfItemNSpecifier;
  374.     TDescriptor positionOfItem;
  375.     TDescriptor someBits;
  376.     TDescriptor someMaskBits;
  377.     TAEvent ae;
  378.     TAEvent reply;
  379.     long count = 0;
  380.     OSErr err = noErr;
  381.     Point    localPosition;
  382.  
  383.     Try
  384.     {
  385.         //
  386.         // Make the address of the finder, and an object specifier to
  387.         // the frontmost window.  We will use these descriptors a number
  388.         // of times.
  389.         //
  390.         target = GetAddressOfFinder();
  391.         frontWindowSpecifier = MakeSpecifierForFrontWindow();
  392.         
  393.         //
  394.         // Get an icon family for the first item in the frontmost window
  395.         // and save it away
  396.         //
  397.         ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  398.         
  399.         //
  400.         // Set the direct object for this event to 'icon of item 1 of frontWindowSpecifier'
  401.         //
  402.         itemNOfFrontWindowSpecifier = MakeSpecifierForIndexedItem(cObject, itemNum, frontWindowSpecifier);
  403.         iconOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pIconBitmap, itemNOfFrontWindowSpecifier);
  404.         ae.PutDescriptor(keyDirectObject, iconOfItemNSpecifier);
  405.         iconOfItemNSpecifier.Dispose();
  406.  
  407.         //
  408.         // See notes on waitreply, elsewhere
  409.         //
  410.         ae.Send(&reply, kAEWaitReply);
  411.         
  412.         //
  413.         // Snarf the icon family out of the reply, and make it an AERecord
  414.         //
  415.         iconFamilyForItem = reply.GetDescriptor(keyAEResult);
  416.         iconFamilyForItem.CoerceInPlace(typeAERecord);
  417.         
  418.         // Get the appropriate bitmaps
  419.         if(gWindowView == pIconBitmap)
  420.         {
  421.             // Try to snarf the icl8 from the family
  422.             someBits = iconFamilyForItem.GetOptionalParameter(key8BitIcon);
  423.             if(!someBits.IsNullDescriptor())
  424.             {
  425.                 HLock(*theBits);
  426.                 someBits.GetBlock(**theBits, kIconSize, type8BitIcon);
  427.                 HUnlock(*theBits);
  428.             }
  429.             else // Ack! no icl8, use the regular ICN# (signaled by making the handle nil)
  430.             {
  431.                 DisposeHandle(*theBits);
  432.                 *theBits = nil;
  433.             }
  434.             
  435.             // Snarf the Mask (really Icon and Mask) from the family
  436.             someMaskBits = iconFamilyForItem.GetOptionalParameter(keyIconAndMask);
  437.             if(someMaskBits.IsNullDescriptor()) // Ack! no ICN#, bail out!
  438.                 return -1;
  439.             HLock(*theMaskBits);
  440.             someMaskBits.GetBlock(**theMaskBits, kMaskSize, typeIconAndMask);
  441.             HUnlock(*theMaskBits);
  442.         }
  443.         else if(gWindowView == pSmallIcon)
  444.         {
  445.             // Try to snarf the ics8 from the family
  446.             someBits = iconFamilyForItem.GetOptionalParameter(keySmall8BitIcon);
  447.             if(!someBits.IsNullDescriptor())
  448.             {
  449.                 HLock(*theBits);
  450.                 someBits.GetBlock(**theBits, kSmallIconSize, typeSmall8BitIcon);
  451.                 HUnlock(*theBits);
  452.             }
  453.             else // Ack! no ics8, use the regular ics# (signaled by making the handle nil)
  454.             {
  455.                 DisposeHandle(*theBits);
  456.                 *theBits = nil;
  457.             }
  458.             
  459.             // Snarf the Mask (really Icon and Mask) from the family
  460.             someMaskBits = iconFamilyForItem.GetOptionalParameter(keySmallIconAndMask);
  461.             if(someMaskBits.IsNullDescriptor()) // Ack! no ics#, bail out!
  462.                 return -1;
  463.             HLock(*theMaskBits);
  464.             someMaskBits.GetBlock(**theMaskBits, kSmallMaskSize, typeSmallIconAndMask);
  465.             HUnlock(*theMaskBits);
  466.         }
  467.         else return -1;
  468.             
  469.         // Clean up icon stuff
  470.         someBits.Dispose();
  471.         someMaskBits.Dispose();
  472.         iconFamilyForItem.Dispose();
  473.         
  474.         
  475.         // Now get the position for the item
  476.         positionOfItemNSpecifier = MakeSpecifierForPropertyOfSpecifier(pPosition, itemNOfFrontWindowSpecifier);
  477.         ae.PutDescriptor(keyDirectObject, positionOfItemNSpecifier);
  478.         positionOfItemNSpecifier.Dispose();
  479.  
  480.         //
  481.         // See notes on waitreply, elsewhere
  482.         //
  483.         ae.Send(&reply, kAEWaitReply);
  484.         
  485.         // Get the position out of the reply
  486.         positionOfItem = reply.GetDescriptor(keyAEResult);
  487.         localPosition = positionOfItem.GetPoint();
  488.         *position = localPosition;
  489.  
  490.         // Cleanup
  491.         positionOfItem.Dispose();
  492.         positionOfItemNSpecifier.Dispose();
  493.         itemNOfFrontWindowSpecifier.Dispose();
  494.         target.Dispose();
  495.         frontWindowSpecifier.Dispose();
  496.     }
  497.     Catch(err)
  498.     {
  499.         //
  500.         // Any of a number of routines that we call above could
  501.         // fail; if they do, we need to dispose of any object
  502.         // that we created.
  503.         //
  504.         // Hah! not really doing it, am I? dkj
  505.         target.Dispose();
  506.         frontWindowSpecifier.Dispose();
  507.         
  508.         Throw(err);
  509.     }
  510.     return noErr;
  511. }
  512.  
  513. OSErr GatherFinderInfo(short maxItems)
  514. {
  515.     short    cnt, err;
  516.     Point    windowPosition;
  517.     
  518.     // get the position of, and number of items in, the front window
  519.     GetFrontWindowInfo(&gNumItems, &windowPosition, &gWindowRect, &gWindowView);
  520.     if(gNumItems > maxItems)
  521.         return -1;
  522.     
  523.     for(cnt = 0; cnt < gNumItems; cnt++)
  524.     {
  525.         if(gWindowView == pIconBitmap)
  526.         {
  527.             gIcons[cnt] = NewHandle(kIconSize);
  528.             gMasks[cnt] = NewHandle(kMaskSize);
  529.         }
  530.         else if(gWindowView == pSmallIcon)
  531.         {
  532.             gIcons[cnt] = NewHandle(kSmallIconSize);
  533.             gMasks[cnt] = NewHandle(kSmallMaskSize);
  534.         }
  535.         else return -1;
  536.         
  537.         if(gIcons[cnt] == nil || gMasks[cnt] == nil)
  538.             return -1; // Oooh, no cleaning up
  539.         
  540.         // Get each item's icon and position
  541.         err = GetFinderItemInfo(cnt + 1, &gIcons[cnt], &gMasks[cnt], &gPositions[cnt]);
  542.         if(err) return err;
  543.         
  544.         AddPt(windowPosition, &gPositions[cnt]);
  545.     }
  546.     return noErr;
  547. }        
  548.     
  549.  
  550.  
  551.